/**
 ****************************************************************************
 * Copyright (C) Marcelo F. Ochoa. All rights reserved.                      *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 */

package com.prism.toolkit;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.Writer;

import java.util.Enumeration;

import org.apache.log4j.Logger;

import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Jxtp extends Object {
    static Logger log = null;
    static final String version = "2.1.1.0";

    static StringWriter outBuff = null;

    static boolean notInitialize = true;

    static boolean closeHeader = false;

    public Jxtp() {
    }

    private static void initialize() {
        header((Jxtf.contentType == null) ? Jxtf.defaultContentType :
               Jxtf.contentType);
    }

    public static void free() {
        outBuff = null;
        notInitialize = true;
        closeHeader = false;
        log = null;
    }

    /**
     * Replace char &
     * @return A new String with the original String with &amp; instead of &
     * @param s A URL String with char &
     */
    public static String replace2(String s) {
        for (int i = 0; (i = s.indexOf('&', i)) != -1; i += 4)
            // "&" char
            s = s.substring(0, i + 1) + "amp;" + s.substring(i + 1);
        for (int i = 0; (i = s.indexOf('<', i)) != -1; i += 4)
            // "<" char
            s = s.substring(0, i) + "&lt;" + s.substring(i + 1);
        for (int i = 0; (i = s.indexOf('>', i)) != -1; i += 4)
            // ">" char
            s = s.substring(0, i) + "&gt;" + s.substring(i + 1);
        return s;
    }

    public static void print(String s) {
        if (notInitialize)
            initialize();
        else if (!closeHeader)
            closeHeader();
        try {
            outBuff.write(s + "\n");
        } catch (Exception e) {
            // System.out.println should be in ORACLE_BASE/admin/instance/udump/*.trc files
            log.warn(".print - exception "+e.getMessage(),e);
        }
    }

    public static Writer getWriter() {
        if (notInitialize)
            initialize();
        else if (!closeHeader)
            closeHeader();
        return outBuff;
    }

    public static void print(int i) {
        print("" + i);
    }

    public static void print(float f) {
        print("" + f);
    }

    public static void print(double f) {
        print("" + f);
    }

    public static void print(java.sql.Date d) {
        print("" + d);
    }

    public static void print(long l) {
        print("" + l);
    }

    public static void print(boolean b) {
        print("" + b);
    }

    public static void prn(String s) {
        if (notInitialize)
            initialize();
        else if (!closeHeader)
            closeHeader();
        try {
            outBuff.write(s);
        } catch (Exception e) {
            // System.out.println should be in ORACLE_BASE/admin/instance/udump/*.trc files
            log.warn(".prn - exception "+e.getMessage(),e);
        }
    }

    public static void prn(int i) {
        prn("" + i);
    }

    public static void prn(float f) {
        prn("" + f);
    }

    public static void prn(double f) {
        prn("" + f);
    }

    public static void prn(java.sql.Date d) {
        prn("" + d);
    }

    public static void prn(long l) {
        prn("" + l);
    }

    public static void prn(boolean b) {
        prn("" + b);
    }

    public static void p(String s) {
        print(s);
    }

    public static void p(InputStream r) {
        if (notInitialize)
            initialize();
        else if (!closeHeader)
            closeHeader();
        InputStreamReader in = null;
        int i;
        try {
            in = new InputStreamReader(r);
            char[] buff = new char[1024];
            while ((i = in.read(buff)) > 0) {
                outBuff.write(buff, 0, i);
            }
            in.close();
        } catch (Exception e) {
            // System.out.println should be in ORACLE_BASE/admin/instance/udump/*.trc files
            log.warn(".p - exception "+e.getMessage(),e);
        }
    }

    public static void p(org.w3c.dom.Document doc) {
        printNode(doc, "", true);
    }

    public static void p(org.w3c.dom.Node node) {
        printNode(node, "", true);
    }

    public static void p(org.w3c.dom.Document doc, boolean replaceChar) {
        printNode(doc, "", replaceChar);
    }

    public static void p(org.w3c.dom.Node node, boolean replaceChar) {
        printNode(node, "", replaceChar);
    }

    private static void printNode(Node node, String indent,
                                  boolean replaceChar) {
        switch (node.getNodeType()) {
        case Node.DOCUMENT_NODE :
            // recurse on each child
            NodeList nodes = node.getChildNodes();
            if (nodes != null) {
                for (int i = 0; i < nodes.getLength(); i++) {
                    prn(indent);
                    printNode(nodes.item(i), indent + "  ", replaceChar);
                    prn("\n");
                }
            }
            break;
        case Node.ELEMENT_NODE :
            String name = node.getNodeName();
            NamedNodeMap attributes = node.getAttributes();
            NodeList children = node.getChildNodes();
            if (children.getLength() > 0 &&
                children.item(0).getNodeType() != Node.TEXT_NODE)
                prn("\n" + indent + "<" + name);
            else
                prn("<" + name);
            for (int i = 0; i < attributes.getLength(); i++) {
                Node current = attributes.item(i);
                prn(" " + current.getNodeName() + "=\"" +
                    ((replaceChar) ? replace2(current.getNodeValue()) :
                                                           current.getNodeValue()) +
                    "\"");
            }
            prn(">");
            // recurse on each child
            if (children != null) {
                for (int i = 0; i < children.getLength(); i++) {
                    printNode(children.item(i), indent + "  ", replaceChar);
                }
            }
            prn("</" + name + ">");
            break;
        case Node.TEXT_NODE :
        case Node.CDATA_SECTION_NODE :
            prn(((replaceChar) ? replace2(node.getNodeValue()) :
                 node.getNodeValue()));
            break;
        case Node.PROCESSING_INSTRUCTION_NODE :
            if (node.getNodeValue() != null)
                print("<?" + node.getNodeName() + " " +
                      ((replaceChar) ? replace2(node.getNodeValue()) :
                                                         node.getNodeValue()) +
                      "?>\n");
            break;
        case Node.ENTITY_REFERENCE_NODE :
            prn("&" + node.getNodeName() + ";");
            break;
        }
    }

    public static void setEncoding(String enc) {
        Jxtf.encoding = enc;
    }

    public static String getEncoding() {
        if (Jxtf.encoding == null) {
            // if not encoding already defined, try to use DAD setting
            Jxtf.encoding = Jowa.GETCGIVAR("REQUEST_IANA_CHARSET");
            if (Jxtf.encoding == null)
                // if not DAD setting use default encoding
                Jxtf.encoding = Jxtf.defaultEncoding;
        }
        return Jxtf.encoding;
    }

    public static void setContentType(String contentType) {
        Jxtf.contentType = contentType;
    }

    public static String getContentType() {
        if (Jxtf.contentType==null)
            Jxtf.contentType = Jxtf.defaultContentType;
        return Jxtf.contentType;
    }

    public static void setHeader(String name, String value) {
        if (closeHeader) {
            log.warn(".setHeader - Can not setHeader: " + name +
                     " with value '" + value +
                     "'. HTTP Header already closed.");
            throw new IllegalStateException("Can not setHeader: " + name +
                                            " with value '" + value +
                                            "'. HTTP Header already closed.");
        }
        if (notInitialize) {
            notInitialize = false;
            log = Logger.getLogger(Jxtp.class);
            outBuff = new StringWriter();
        }
        outBuff.write(name + ": " + value + "\n");
    }

    public static void closeHeader() {
        if (notInitialize)
          initialize();
        if (closeHeader) {
            log.warn(".setHeader - Can not closeHeader. HTTP Header already closed.");
            throw new IllegalStateException("Can not closeHeader. HTTP Header already closed.");
        } else
            outBuff.write("\n");
        closeHeader = true;
    }

    public static void header(String contentType) {
        header(contentType, true);
    }

    public static void header(String contentType, boolean bcloseHeader) {
        if (Jxtf.encoding == null) {
            // if not encoding already defined, try to use DAD setting
            Jxtf.encoding = Jowa.GETCGIVAR("REQUEST_IANA_CHARSET");
            if (Jxtf.encoding == null)
                // if not DAD setting use default encoding
                Jxtf.encoding = Jxtf.defaultEncoding;
        }
        Jxtf.contentType = contentType;
        try {
            setHeader("Content-type",
                      contentType + "; charset=" + Jxtf.encoding);
            if (bcloseHeader)
                closeHeader();
        } catch (Exception e) {
            // System.out.println should be in ORACLE_BASE/admin/instance/udump/*.trc files
            log.warn(".header - exception "+e.getMessage(),e);
        }
    }

    public static void prolog() {
        if (notInitialize)
            initialize();
        print(Jxtf.prolog());
    }

    public static void prolog(String version) {
        if (notInitialize)
            initialize();
        print(Jxtf.prolog(version));
    }

    public static void epilog() {
        print(Jxtf.epilog());
    }

    public static void tag(String name, String value) {
        print(Jxtf.tag(name, value));
    }

    public static void tag(String name, String value, String attr) {
        print(Jxtf.tag(name, value, attr));
    }

    public static void tagOpen(String name) {
        prn(Jxtf.tagOpen(name));
    }

    public static void tagOpen(String name, String attr) {
        prn(Jxtf.tagOpen(name, attr));
    }

    public static void tagClose(String name) {
        print(Jxtf.tagClose(name));
    }

    public static void redirecUrl(String url) {
        setHeader("Location", url);
    }

    public static void notAuthorized(String realm) {
        setHeader("WWW-authenticate", realm);
    }

    public static void removeCookie(String name) {
        java.sql.Date oldDate = new java.sql.Date(0);
        sendCookie(name, "none", oldDate);
        Jowa.parsedCookies.remove(name);
    }

    public static void sendCookie(String name, String value) {
        setHeader("Set-Cookie", name + "=" + value + ";");
        if (Jowa.parsedCookies==null)
          Jowa.parseCookies();
        Jowa.parsedCookies.put(name,value);
    }

    public static void sendCookie(String name, String value,
                                  java.sql.Date expires) {
        java.text.DateFormat df =
            new java.text.SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss zzz",
                                                                 java.util
                                                                 .Locale.US);
        String myDate = df.format(expires);
        setHeader("Set-Cookie",
                  name + "=" + value + "; " + "expires=" + myDate + ";");
        if (Jowa.parsedCookies==null)
          Jowa.parseCookies();
        Jowa.parsedCookies.put(name,value);
    }

    public static void sendCookie(String name, String value,
                                  java.sql.Date expires, String path) {
        java.text.DateFormat df =
            new java.text.SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss zzz",
                                                                 java.util
                                                                 .Locale.US);
        String myDate = df.format(expires);
        setHeader("Set-Cookie",
                  name + "=" + value + "; " + "expires=" + myDate + "; " +
                  "path=" + path);
        if (Jowa.parsedCookies==null)
          Jowa.parseCookies();
        Jowa.parsedCookies.put(name,value);
    }

    public static void sendCookie(String name, String value,
                                  java.sql.Date expires, String path,
                                  String domain, boolean secure) {
        java.text.DateFormat df =
            new java.text.SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss zzz",
                                                                 java.util
                                                                 .Locale.US);
        String myDate = df.format(expires);
        setHeader("Set-Cookie",
                  name + "=" + value + "; " + "expires=" + myDate + "; " +
                  "domain=" + domain + "; " + "path=" + path +
                  (secure ? "; secure " : ""));
        if (Jowa.parsedCookies==null)
          Jowa.parseCookies();
        Jowa.parsedCookies.put(name,value);
    }

    public static String getCookie(String name) {
        if (Jowa.parsedCookies==null)
          Jowa.parseCookies();
        return (String)Jowa.parsedCookies.get(name);
    }

    public static Enumeration getAllCookies() {
        if (Jowa.parsedCookies==null)
          Jowa.parseCookies();
        return Jowa.parsedCookies.elements();
    }
}
